package cn.android666.ping

import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import cn.android666.ping.databinding.ActivityMainBinding
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.util.regex.Pattern
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var mAdapter: MyAdapter
    private val lines = ArrayList<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        mAdapter = MyAdapter()
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
        binding.recyclerView.adapter = mAdapter
        binding.btnStartPing.setOnClickListener {
            thread { ping() }
        }
    }

    private fun ping() {
        val ip = binding.etIp.text.trim().toString()
        val sizeStr = binding.etSize.text.trim().toString()
        val time = binding.etTime.text.trim().toString()
        if (ip.isBlank()) {
            runOnUiThread { Toast.makeText(this, "请输入IP", Toast.LENGTH_SHORT).show() }
            return
        }
        if (sizeStr.isBlank()) {
            runOnUiThread { Toast.makeText(this, "请输入数据包大小", Toast.LENGTH_SHORT).show() }
            return
        }
        if (time.isBlank()) {
            runOnUiThread { Toast.makeText(this, "请输入要ping多久", Toast.LENGTH_SHORT).show() }
            return
        }

        if (!isValidIpAddress(ip)) {
            runOnUiThread {
                AlertDialog.Builder(this)
                    .setTitle("提示")
                    .setMessage("您输入的IP地址格式有误，请修正！")
                    .show()
            }
            return
        }

        runOnUiThread {
            binding.btnStartPing.isEnabled = false
            lines.clear()
            addData("Ping开始")
        }

        val size = sizeStr.toInt() - 8
        val command = "ping -s $size -w $time $ip"

        // 注：正常ping数据和错误ping数据可能会交替输出，所以需要开两个线程同时读取
        val process = Runtime.getRuntime().exec(command)
        val inputStreamThread = readData(process.inputStream) // 读取正常ping数据
        val errorStreamThread = readData(process.errorStream) // 读取错误ping数据

        // 等待两个读取线程结束
        inputStreamThread.join()
        errorStreamThread.join()

        runOnUiThread {
            addData("Ping结束")
            binding.btnStartPing.isEnabled = true
        }
    }

    private fun readData(inputStream: InputStream?) = thread {
        try {
            BufferedReader(InputStreamReader(inputStream)).use { reader ->
                var line: String?
                while (reader.readLine().also { line = it } != null) {
                    val lineTemp = line!!
                    runOnUiThread { addData(lineTemp) } // 这里切换到了UI线程，子线程继续执行时可以已经把line对象又赋值为null了，所以使用了lineTemp来预防值被重新赋值
                }
            }
        } catch (e: Exception) {
            runOnUiThread { addData("出现异常：${e.javaClass.simpleName}: ${e.message}") }
        }
    }

    private fun addData(data: String) {
        lines.add(data)
        refreshListView()
    }

    private fun refreshListView() {
        mAdapter.notifyDataSetChanged()
        binding.recyclerView.scrollToPosition(lines.size - 1)
    }

    /**
     * 验证给定的ip地址是否有效
     * @param ip
     */
    private fun isValidIpAddress(ip: String?): Boolean {
        if (ip.isNullOrBlank()) return false
        val regex = "(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})(\\.(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})){3}"
        val pattern = Pattern.compile(regex)
        val matcher = pattern.matcher(ip)
        return matcher.matches()
    }

    internal inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var textView: TextView = itemView.findViewById(android.R.id.text1) as TextView
    }

    internal inner class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            return MyViewHolder(View.inflate(parent.context, android.R.layout.simple_list_item_1,null))
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.textView.text = lines[position]
        }

        override fun getItemCount(): Int {
            return lines.size
        }
    }
}